package com.seu.me.thread.day5.concurrent019;

import java.io.IOException;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created by liangfeihu on 2017/11/24.
 */
public class UseCyclicBarrier {

    /**
     * 1、CyclicBarrier 的字面意思是可循环（Cyclic）使用的屏障（Barrier）。
     * 2、它要做的事情是，让一组线程到达一个屏障（也可以叫同步点）时被阻塞，直到最后一个线程到达屏障时，屏障才会开门，
     * 所有被屏障拦截的线程才会继续干活。线程进入屏障通过CyclicBarrier的await()方法。
     * 3、CyclicBarrier默认的构造方法是CyclicBarrier(int parties)，其参数表示屏障拦截的线程数量，每个线程调用await方法
     * 告诉CyclicBarrier我已经到达了屏障，然后当前线程被阻塞。
     * 4、CyclicBarrier还提供一个更高级的构造函数CyclicBarrier(int parties, Runnable barrierAction)，用于在线程到达屏障时，
     * 优先执行barrierAction这个Runnable对象，方便处理更复杂的业务场景。
     */
    static class Runner implements Runnable {
        private CyclicBarrier barrier;
        private String name;

        public Runner(CyclicBarrier barrier, String name) {
            this.barrier = barrier;
            this.name = name;
        }

        @Override
        public void run() {
            try {
                int sleep = (new Random()).nextInt(8) + 1;
                Thread.sleep(1000 * sleep);
                System.out.println(name + " sleep " + sleep + " 秒后" + "准备OK");
                barrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
            System.out.println(name + " Go!!");
        }
    }

    public static void main(String[] args) throws IOException, InterruptedException {
        CyclicBarrier barrier = new CyclicBarrier(3);
        ExecutorService executor = Executors.newFixedThreadPool(3);

        executor.submit(new Thread(new Runner(barrier, "ZhangSan")));
        executor.submit(new Thread(new Runner(barrier, "LiSi")));
        executor.submit(new Thread(new Runner(barrier, "WangWu")));

        executor.shutdown();
    }

}  